<template>
  <div id="WebGL-output"></div>
  <div id="Stats-output"></div>
</template>

<script setup>
import {getCurrentInstance, onMounted, reactive} from 'vue';
import {OrbitControls} from 'three/examples/jsm/controls/OrbitControls';
import {gui as dat} from 'dat.gui';
import Stats from 'three/examples/jsm/libs/stats.module';

let {proxy} = getCurrentInstance();
let THREE = proxy.$THREE;

let scene = reactive({})
let camera = reactive({})
let renderer = reactive({})
let sphere1 = reactive({})
let sphere2 = reactive({})
let spotLight = reactive({})
let plane = reactive({})
let axesHelper = reactive({})
let gridHelper = reactive({})
let controls = reactive({})
let sphereMaterial1 = reactive({})
let sphereMaterial2 = reactive({})
let planeMaterial = reactive({})

// 初始化
function initThree() {
  // 创建场景
  scene = new THREE.Scene();
  // 创建照相机
  camera = new THREE.PerspectiveCamera(45, window.innerWidth / window.innerHeight, 0.1, 10000);
  // 配置相机
  camera.position.set(200, 150, 200);// 相机在三维空间的位置
  // camera.lookAt(scene.position); // 将相机指向场景
  camera.lookAt(new THREE.Vector3(0, 0, 0)); // 相机看向空间坐标原点

  // 创建渲染器 (画布)
  renderer = new THREE.WebGLRenderer();
  // 配置渲染器
  renderer.antialias = true;// 抗锯齿
  renderer.autoClear = true;// 自动清除
  renderer.setClearColor(0x050505); // canvas画布颜色
  renderer.setSize(window.innerWidth, window.innerHeight); // canvas 画布大小
  renderer.shadowMap.enabled = true; // 让渲染器支持投影

  //辅助线 X轴是红色. Y轴是绿色. Z轴是蓝色
  axesHelper = new THREE.AxesHelper(100);
  scene.add(axesHelper);

  // 创建网格辅助
  gridHelper = new THREE.GridHelper(1200, 50, 0xFF4444, 0x404040);
  // scene.add(gridHelper);

  createSphere1(); //球体1
  createSphere2(); //球体2
  createPlane(); //地面
  createLight(); //灯光
  createPoint(); //光源

  // 绕轴旋转
  const pivotPoint = new THREE.Object3D();
  pivotPoint.add(sphere2);
  sphere1.add(pivotPoint);

  // 将这个canvas元素插入到 html中
  document.getElementById('WebGL-output').appendChild(renderer.domElement);
  renderer.render(scene, camera)
}

// 创建球体
function createSphere1() {
  let sphereGeometry1 = new THREE.SphereGeometry(10, 100, 100); //半径、宽高
  sphereMaterial1 = new THREE.MeshLambertMaterial({color: Math.random() * 0xffffff}); //材质颜色
  sphere1 = new THREE.Mesh(sphereGeometry1, sphereMaterial1);
  sphere1.position.y = 40;
  sphere1.castShadow = true; //球体投影
  scene.add(sphere1);
}

function createSphere2() {
  let sphereGeometry2 = new THREE.SphereGeometry(15, 100, 100); //半径、宽高
  sphereMaterial2 = new THREE.MeshLambertMaterial({color: Math.random() * 0xffffff}); //材质颜色
  sphere2 = new THREE.Mesh(sphereGeometry2, sphereMaterial2);
  sphere2.position.z = 100;
  sphere2.castShadow = true; //球体投影
  scene.add(sphere2);
}

// 创建灯光
function createLight() {
  const ambientLight = new THREE.AmbientLight({color: 0x404040});
  const directionalLight1 = new THREE.DirectionalLight( 0xC0C090 );
  const directionalLight2 = new THREE.DirectionalLight( 0xC0C090 );
  // 设置光源的位置
  directionalLight1.position.set(-300, -400, 300);
  directionalLight2.position.set(300, 400, -300);
  // 将光源加入场景
  scene.add(ambientLight);
  scene.add(directionalLight1);
  scene.add(directionalLight2);
}

// 添加光源
function createPoint() {
  spotLight = new THREE.SpotLight(0xcccccc); //设置灯光的颜色
  spotLight.position.set(-100, 300, 10); //点光源位置
  // spotLight.angle = Math.PI / 10; //设置投影的程度
  spotLight.shadow.mapSize.set(2048, 2048);     // 定义阴影的分辨率
  spotLight.castShadow = true; //灯光投影
  scene.add(spotLight);
}

// 创建地面
function createPlane() {
  let planeGeometry = new THREE.PlaneGeometry(500, 500);   //地面的材质，宽高
  planeMaterial = new THREE.MeshLambertMaterial({color: 0x6D6565});  // 创建地面
  plane = new THREE.Mesh(planeGeometry, planeMaterial); // 设置地面的位置
  plane.receiveShadow = true; //地面被投影

  // 绕x轴旋转90度
  plane.rotation.x = -0.5 * Math.PI;
  plane.position.x = 0;
  plane.position.y = 0;
  plane.position.z = 0;
  scene.add(plane);  //将地面添加到坐标轴中
}

function initControls() {
  controls = new OrbitControls(camera, renderer.domElement)
  // 球体1可调节属性
  controls.sphere1RotationSpeed = 0.01
  controls.sphere1PositionX = 0
  controls.sphere1PositionY = 40
  controls.sphere1PositionZ = 0
  controls.sphere1Wireframe = sphereMaterial1?.wireframe // 网格几何体
  controls.sphere1Color = sphereMaterial1?.color?.getStyle();
  // 球体2可调节属性
  controls.sphere2PositionX = 0
  controls.sphere2PositionY = 40
  controls.sphere2PositionZ = 100
  controls.sphere2Wireframe = sphereMaterial2?.wireframe // 网格几何体
  controls.sphere2Color = sphereMaterial2?.color?.getStyle();

  // 平面可调节属性
  controls.planeColor = planeMaterial.color.getStyle()

  // 场景可调节属性
  // controls.sceneBackground = renderer.getClearColor().getHex()
  // controls.spotLight = true
  controls.sphere1 = true
  controls.sphere2 = true
  controls.plane = false
  controls.axesHelper = false
  controls.gridHelper = true
  // controls.selectMesh = ''
}
// 初始化性能插件方法
function initStats() {
  const stats = new Stats();

  stats.setMode(0);// 0:现实fps, 1:ms

  // 调整插件布局
  stats.domElement.style.position = 'absolute';
  stats.domElement.style.left = '0px';
  stats.domElement.style.top = '0px';
  // 加入画布
  document.getElementById('Stats-output').append(stats.domElement);
  // 将初始化的插件返回
  return stats;
}
// 初始化GUI
function initGUI() {
  // 创建图形调试控件
  const gui = new dat.GUI({autoPlace: false})
  // 添加id
  gui.domElement.id = 'gui-box'
  // 球体1对象调试栏目
  const sphere1Controls = gui.addFolder('球体1控制')
  sphere1Controls.add(controls, 'sphere1RotationSpeed', 0.01, 100)
  sphere1Controls.add(controls, 'sphere1PositionX', -200, 200)
  sphere1Controls.add(controls, 'sphere1PositionY', -200, 200)
  sphere1Controls.add(controls, 'sphere1PositionZ', -200, 200)
  sphere1Controls.add(controls, 'sphere1Wireframe').onChange((e) => {
    sphereMaterial1.wireframe = e
  })
  sphere1Controls.addColor(controls, 'sphere1Color').onChange((e) => {
    sphereMaterial1.color.setStyle(e)
  })
  // 球体2对象调试栏目
  const sphere2Controls = gui.addFolder('球体2控制')
  sphere2Controls.add(controls, 'sphere2PositionX', -200, 200)
  sphere2Controls.add(controls, 'sphere2PositionY', -200, 200)
  sphere2Controls.add(controls, 'sphere2PositionZ', -200, 200)
  sphere2Controls.add(controls, 'sphere2Wireframe').onChange((e) => {
    sphereMaterial1.wireframe = e
  })
  sphere2Controls.addColor(controls, 'sphere2Color').onChange((e) => {
    sphereMaterial2.color.setStyle(e)
  })
  // 地面对象调试栏目
  const planeControls = gui.addFolder('地面控制')
  planeControls.addColor(controls, 'planeColor').onChange((e) => {
    planeMaterial.color.setStyle(e)
  })
  // 场景对象调试栏目
  const sceneControls = gui.addFolder('场景控制')
  /*  sceneControls.addColor(controls, 'sceneBackground').onChange((e) => {
      renderer.setClearColor(e)
    })*/
/*  sceneControls.add(controls, 'spotLight').onChange((e) => {
    e ? scene.add(spotLight) : scene.remove(spotLight)
  })*/
  sceneControls.add(controls, 'plane').onChange((e) => {
    e ? scene.add(plane) : scene.remove(plane)
  })
  sceneControls.add(controls, 'axesHelper').onChange((e) => {
    e ? scene.add(axesHelper) : scene.remove(axesHelper)
  })
  sceneControls.add(controls, 'gridHelper').onChange((e) => {
    e ? scene.add(gridHelper) : scene.remove(gridHelper)
  })
/*  sceneControls.add(controls, 'selectMesh', ['sphere1', 'sphere2']).onChange((e) => {
    scene.remove(sphere1)
    scene.remove(sphere2)
    switch (e) {
      case 'sphere1':
        scene.add(sphere1)
        break;
      case 'sphere2':
        scene.add(sphere2)
        break;
    }
    scene.add(e);
  })*/
  // 调整插件布局
  gui.domElement.style.position = 'absolute'
  gui.domElement.style.right = '0px'
  gui.domElement.style.top = '50px'
  document.getElementById('WebGL-output').append(gui.domElement)
}

function render() {
  // 旋转速度动态设置
  // sphere1.rotation.x += controls.sphere1RotationSpeed
  sphere1.rotation.y += controls.sphere1RotationSpeed
  // sphere1.rotation.z += controls.sphere1RotationSpeed
  // 球体1动态设置位置
  sphere1.position.x = controls.sphere1PositionX
  sphere1.position.y = controls.sphere1PositionY
  sphere1.position.z = controls.sphere1PositionZ
  // 球体2动态设置位置
  sphere2.position.x = controls.sphere2PositionX
  sphere2.position.y = controls.sphere2PositionY
  sphere2.position.z = controls.sphere2PositionZ
  // 开始渲染
  renderer.render(scene, camera);
}

function animate() {
  requestAnimationFrame(animate)
  render()
}

// 窗口大小改变触发的方法
function onWindowResize() {
  // 改变相机的 aspect 为窗口的宽和长度之比
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新相机的投影矩阵
  camera.updateProjectionMatrix();
  // 重新设置渲染器的大小
  renderer.setSize(window.innerWidth, window.innerHeight);
}

onMounted(() => {
  initThree()
  initControls()
  initGUI()
  const stats = initStats()
  stats.update()
  animate(stats)
  // 添加事件监听
  window.addEventListener('resize', onWindowResize, false);
})
</script>

<style scoped>

</style>
